/*
******************************************************************************************************* 
**  Copyright (C) 2019, 苏州检易生物科技有限公司 
**  All rights reserved. 
** 
**  FileName:       	spi.c
**  Description:	
**  Author:        	 
**  Version				v0.1
**  Date:           	2019-06-21
**	Function List： 
**  History:         
*********************************************************************************************************
*/


/*
*********************************************************************************************************
*                                              	调试开关
*********************************************************************************************************
*/


/*
*********************************************************************************************************
*                                             INCLUDE FILES
*********************************************************************************************************
*/
#include "spi.h"
#include "log_console.h"
#ifdef RTOS
#include <rtthread.h>
#include <rthw.h>
#endif


/*
*********************************************************************************************************
*                                              	宏定义
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*                                              	结构体定义
*********************************************************************************************************
*/

 
/*
*********************************************************************************************************
*                                              	函数原型声明
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*                                              	全局变量定义
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*                                              	模块静态变量定义
*********************************************************************************************************
*/
static spi_handle_t spi5_handle;


/*
*********************************************************************************************************
*                                              	函数定义
*********************************************************************************************************
*/

spi_handle_t* spi_open(SPI_TypeDef * spi)
{
	GPIO_InitTypeDef  GPIO_InitStruct;
	GPIO_InitStruct.Mode=GPIO_MODE_AF_PP;
	GPIO_InitStruct.Speed=GPIO_SPEED_FREQ_HIGH;
	GPIO_InitStruct.Pull=GPIO_NOPULL;
	spi_handle_t* spi_handle=NULL;
	switch((uint32_t)spi){
		case (uint32_t)SPI5:{
			spi_handle = &spi5_handle;
//			if(spi_handle->spi_status != SPI_STATUS_UNINIT)
//				break;
			__HAL_RCC_GPIOF_CLK_ENABLE();
			__HAL_RCC_SPI5_CLK_ENABLE();
			GPIO_InitStruct.Pin=GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9;
			GPIO_InitStruct.Alternate=GPIO_AF5_SPI5;
			HAL_GPIO_Init(GPIOF,&GPIO_InitStruct);
			
			spi_handle->spi_hal_handle.Instance               = spi;
			spi_handle->spi_hal_handle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
			spi_handle->spi_hal_handle.Init.Direction         = SPI_DIRECTION_2LINES;
			spi_handle->spi_hal_handle.Init.CLKPhase          = SPI_PHASE_1EDGE;
			spi_handle->spi_hal_handle.Init.CLKPolarity       = SPI_POLARITY_LOW;
			spi_handle->spi_hal_handle.Init.DataSize          = SPI_DATASIZE_8BIT;
			spi_handle->spi_hal_handle.Init.FirstBit          = SPI_FIRSTBIT_MSB;
			spi_handle->spi_hal_handle.Init.TIMode            = SPI_TIMODE_DISABLE;
			spi_handle->spi_hal_handle.Init.CRCCalculation    = SPI_CRCCALCULATION_DISABLE;
			spi_handle->spi_hal_handle.Init.CRCPolynomial     = 7;
			spi_handle->spi_hal_handle.Init.CRCLength         = SPI_CRC_LENGTH_8BIT;
			spi_handle->spi_hal_handle.Init.NSS               = SPI_NSS_SOFT;
			spi_handle->spi_hal_handle.Init.NSSPMode          = SPI_NSS_PULSE_DISABLE;
			spi_handle->spi_hal_handle.Init.FifoThreshold     = SPI_FIFO_THRESHOLD_01DATA;
			spi_handle->spi_hal_handle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE;  
			spi_handle->spi_hal_handle.Init.Mode 							= SPI_MODE_MASTER;
			
//			if (HAL_SPI_DeInit(&spi_handle->spi_hal_handle) != HAL_OK)
//			{
//			}	
			if(HAL_SPI_Init(&spi_handle->spi_hal_handle) != HAL_OK)
			{
				Trace_Log("SPI hw init failed!\r\n");
				break;
			}
//			else
//				spi_handle->spi_status=SPI_STATUS_IDLE;
			return spi_handle;
		}
		default:return spi_handle;
	}
	return spi_handle;
}
spi_err_t  spi_close(SPI_TypeDef * spi)
{
	switch((uint32_t)spi){
		case (uint32_t)SPI5:{
			__HAL_RCC_SPI2_FORCE_RESET();
			__HAL_RCC_SPI2_RELEASE_RESET();
			break;
		}
		default:break;
	}
}
spi_err_t spi_dma_init(spi_handle_t* spi_handle,spi_dma_callback callback)
{
	if(NULL == spi_handle)
		return SPI_ERR_FORM;
	switch((uint32_t) spi_handle->spi_hal_handle.Instance){
		case (uint32_t)SPI5:{
			spi_handle->spi_dma_tx_handle.Instance=SPI5_TX_DMA_STREAM;
			spi_handle->spi_dma_tx_handle.Init.Request=DMA_REQUEST_SPI5_TX;
			spi_handle->spi_dma_tx_handle.Init.Direction=DMA_MEMORY_TO_PERIPH;
			spi_handle->spi_dma_tx_handle.Init.PeriphInc=DMA_PINC_DISABLE;
			spi_handle->spi_dma_tx_handle.Init.MemInc=DMA_MINC_ENABLE;
			spi_handle->spi_dma_tx_handle.Init.PeriphDataAlignment=DMA_PDATAALIGN_BYTE;
			spi_handle->spi_dma_tx_handle.Init.MemDataAlignment=DMA_MDATAALIGN_BYTE;
			spi_handle->spi_dma_tx_handle.Init.Mode=DMA_NORMAL;
			spi_handle->spi_dma_tx_handle.Init.Priority=DMA_PRIORITY_MEDIUM;
			spi_handle->spi_dma_tx_handle.Init.FIFOMode=DMA_FIFOMODE_DISABLE;
			spi_handle->spi_dma_tx_handle.Init.FIFOThreshold=DMA_FIFO_THRESHOLD_FULL;
			spi_handle->spi_dma_tx_handle.Init.MemBurst=DMA_MBURST_SINGLE;
			spi_handle->spi_dma_tx_handle.Init.PeriphBurst=DMA_PBURST_SINGLE;
			
			spi_handle->spi_dma_rx_handle=spi_handle->spi_dma_tx_handle;
			spi_handle->spi_dma_rx_handle.Instance=SPI5_RX_DMA_STREAM;
			spi_handle->spi_dma_rx_handle.Init.Request=DMA_REQUEST_SPI5_RX;
			spi_handle->spi_dma_rx_handle.Init.Direction=DMA_PERIPH_TO_MEMORY;
			
			HAL_DMA_Init(&spi_handle->spi_dma_tx_handle);	
			HAL_DMA_Init(&spi_handle->spi_dma_rx_handle);
			
			__HAL_LINKDMA(&spi_handle->spi_hal_handle, hdmatx, spi_handle->spi_dma_tx_handle);
			__HAL_LINKDMA(&spi_handle->spi_hal_handle, hdmarx, spi_handle->spi_dma_rx_handle);

//			__HAL_DMA_ENABLE_IT(&spi_handle->spi_dma_tx_handle,DMA_IT_TC);
			HAL_NVIC_SetPriority(SPI5_TX_DMA_IRQ, 3, 3);
			HAL_NVIC_EnableIRQ(SPI5_TX_DMA_IRQ);
//			__HAL_DMA_ENABLE_IT(&spi_handle->spi_dma_rx_handle,DMA_IT_TC);
			HAL_NVIC_SetPriority(SPI5_RX_DMA_IRQ, 2, 2);
			HAL_NVIC_EnableIRQ(SPI5_RX_DMA_IRQ);
			
			HAL_NVIC_SetPriority(SPI5_IRQn, 2, 2);
			HAL_NVIC_EnableIRQ(SPI5_IRQn);
		
//			spi_handle->spi_dma_rx_callback=rx_callback;
			spi_handle->spi_dma_callback=callback;
			
//			SET_BIT(spi_handle->spi_hal_handle.Instance->CFG1, SPI_CFG1_RXDMAEN);
//			SET_BIT(spi_handle->spi_hal_handle.Instance->CFG1, SPI_CFG1_TXDMAEN);
			break;}
		default:return SPI_ERR_FORM;
		
	}
	return SPI_ERR_NONE;
}
spi_err_t  spi_write(spi_handle_t* handle, uint8_t* buf, uint16_t size)
{
	if(handle == NULL || buf == NULL)
		return SPI_ERR_FORM;
	HAL_SPI_Transmit(&handle->spi_hal_handle, buf, size, 100);
	return SPI_ERR_NONE;
}

spi_err_t  spi_read(spi_handle_t* handle, uint8_t* buf, uint16_t size)
{
	if(handle == NULL || buf == NULL)
		return SPI_ERR_FORM;
	HAL_SPI_Receive(&handle->spi_hal_handle, buf, size, 100);
	return SPI_ERR_NONE;
}
spi_err_t spi_transfer_receive(spi_handle_t* handle, uint8_t* txbuff,uint8_t * rxbuff,uint16_t size)
{
	if(handle == NULL || NULL==txbuff || NULL==rxbuff)
		return SPI_ERR_FORM;
	HAL_SPI_TransmitReceive(&handle->spi_hal_handle, txbuff,rxbuff, size, 100);
	return SPI_ERR_NONE;
}
spi_err_t spi_dma_transfer(spi_handle_t* handle,uint8_t * txbuff,uint8_t * rxbuff,uint16_t size)
{
	ASSERT(handle);
	ASSERT(handle);
	ASSERT(handle);
	ASSERT(size != 0);
	handle->txbuff = txbuff;
	handle->rxbuff = rxbuff;
	handle->txsize = size;
	handle->rxsize = size;
	if(HAL_SPI_TransmitReceive_DMA(&handle->spi_hal_handle, (uint8_t*)txbuff, (uint8_t *)rxbuff, size) != HAL_OK)
	{
		return SPI_ERR_TRANS;
	}
	return SPI_ERR_NONE;
//	if(NULL!=txbuff)
//	{
//		handle->txbuff=txbuff;
//		handle->txsize=size;
//		HAL_DMA_Start(&handle->spi_dma_tx_handle,(uint32_t)handle->txbuff,
//		(uint32_t)&handle->spi_hal_handle.Instance->TXDR,handle->txsize);
//		__HAL_DMA_ENABLE_IT(&handle->spi_dma_tx_handle,DMA_IT_TC);
//	}
//	if(NULL!=rxbuff)
//	{
//		handle->rxbuff=rxbuff;
//		handle->rxsize=size;
//		HAL_DMA_Start(&handle->spi_dma_rx_handle,
//		(uint32_t)&handle->spi_hal_handle.Instance->RXDR,(uint32_t)handle->rxbuff,handle->rxsize);
//		__HAL_DMA_ENABLE_IT(&handle->spi_dma_rx_handle,DMA_IT_TC);
//	}
}
void SPI5_TX_DMA_IRQ_HANDLER(void)
{
#ifdef RTOS
	rt_interrupt_enter();
#endif
	HAL_DMA_IRQHandler(&spi5_handle.spi_dma_tx_handle);
#ifdef RTOS
	rt_interrupt_leave(); 
#endif	
}
void SPI5_RX_DMA_IRQ_HANDLER(void)
{
#ifdef RTOS
	rt_interrupt_enter();
#endif
	HAL_DMA_IRQHandler(&spi5_handle.spi_dma_rx_handle);
#ifdef RTOS
	rt_interrupt_leave(); 
#endif	
}
uint8_t spi_transfer_byte(spi_handle_t* handle,uint8_t txbyte)
{
	uint8_t rxbyte;
	spi_transfer_receive(handle,(uint8_t*)&txbyte ,(uint8_t*)&rxbyte,1);
	return rxbyte;
}
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
	spi_handle_t* handle;
	switch((uint32_t)hspi->Instance)
	{
		case (uint32_t)SPI5:handle = &spi5_handle;break;
		default:return;
	}
  SCB_InvalidateDCache_by_Addr ((uint32_t *)handle->txbuff, handle->txsize);
  SCB_InvalidateDCache_by_Addr ((uint32_t *)handle->rxbuff, handle->rxsize);
	if(handle->spi_dma_callback)
	{
		handle->spi_dma_callback(handle,handle->rxbuff,handle->rxsize);
	}
}
void SPI5_IRQHandler(void)
{
#ifdef RTOS
	rt_interrupt_enter();
#endif
	HAL_SPI_IRQHandler(&spi5_handle.spi_hal_handle);
#ifdef RTOS
	rt_interrupt_leave(); 
#endif	
}